// Created: Dec 14, 2014
//
// Author: wjinwen.1988@gmail.com

#ifndef CHI_NET_TLS_CONNECTION_H
#define CHI_NET_TLS_CONNECTION_H

#include <openssl/ssl.h>

#include "chi/net/inet_address.h"
#include "chi/net/callbacks.h"
#include "chi/net/buffer.h"
#include "chi/net/tcpconnection.h"

namespace chi {
namespace net {

class Channel;
class EventLoop;
class Socket;

// TLS connection, for tls server usage.
class TLSConnection : public TcpConnection {
 public:
  TLSConnection(SSL* ,  // openssl session 
                EventLoop* loop,  // 事件管理对象指针
                const std::string& name,  // 连接名
                int sockfd,               // socket
                const InetAddress& local_addr,
                const InetAddress& peer_addr);
  virtual ~TLSConnection();

  TLSConnection(const TLSConnection&) = delete;
  void operator=(const TLSConnection&) = delete;

  virtual bool connected() const override
  { return state_ == StateE::kConnected && 
    ssl_state_ == SSLStateEnum::STATE_ESTABLISHED; }

  virtual void Send(const std::string& message);
  virtual void Send(const void* data, size_t len);
  virtual void Send(Buffer& message);

  // start TLS accept
  void SSLAccept();

  enum SSLStateEnum {
    STATE_UNINIT,
    STATE_ACCEPTING,
    STATE_ESTABLISHED,
    STATE_CLOSING,
    STATE_CLOSED,
    STATE_ERROR
  };
  SSLStateEnum ssl_state() const { return ssl_state_; }

 protected:
  // socket可读回调
  virtual void HandleRead();
  // socket可写回调
  virtual void HandleWrite();
  // 连接断开回调
  virtual void HandleClose();
  // socket错误回调
  virtual void HandleError();

  // 把发送消息/关闭连接的动作放到EventLoop内执行，
  // 保证所有的操作都能在同一个线程内执行。
  virtual void SendInLoop(const std::string& message);
  virtual void RealSend(const void* data, size_t len);

 private:
  // check if we need to block accept.
  bool WillBlock(int ret, int *error_out) noexcept;

  // Handle TLS accept
  void HandleAccept();

  void PerformRead();
  void PerformWrite();

  SSLStateEnum ssl_state_;  // TLS连接状态
  SSL* ssl_;                // openssl session
};

typedef std::shared_ptr<TLSConnection> TLSConnectionPtr;

} 
}

#endif
